package org.jdk.learning.thread;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

/**
 * @author xin
 * @version 1.0
 */
public class AQSDemo {

    public static void main(String[] args) {
        int count = 5;
        final ReentrantLock lock = new ReentrantLock(true);
        ExecutorService executorService = Executors.newFixedThreadPool(count);
        IntStream.range(0, count).forEach(i -> executorService.execute(new Runner1(lock, "线程" + i)));

        executorService.shutdown();
    }
}

class Runner1 implements Runnable {

    private ReentrantLock lock;

    private String name;

    Runner1(ReentrantLock lock, String name) {
        this.lock = lock;
        this.name = name;
    }

    @Override
    public void run() {
        /*
         *
         * 1.第一个线程尝试lock的时候，可以成功获得锁，不用进入AQS等待队列，直接返回；
         *
         * 2.第二个线程尝试lock的时候，此时锁已经被第一个线程获取，且还未释放，则第二个线程进入AQS等待队列，在初始化队列时，
         * head节点是一个head.thread=null的节点，等待获取锁的线程插入队列尾部，此时是直接插入head后面，且设置head.waitStatus=SIGNAL,
         * 然后第二个线程进入park状态；
         *
         * 3.第三个线程尝试lock的时候，此时锁还未被第一个线程释放，则第三个队列进入AQS等待队列，且直接插入队列尾部，此时时插入到线程2后面，
         * 且设置线程2的waitStatus=SIGNAL，然后park；
         *
         * 4.当第一个线程释放锁时，会unpark头部的下一个节点，即head.next，即第二个线程，且设置head.next.thread=null,head=head.next，
         * 这样依次唤醒AQS队列。
         *
         */
        lock.lock();

        try {
            System.out.println(name + "获得锁");
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
